package com.engine4cloud.tdf.supervision.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.engine4cloud.tdf.admin.api.dto.AreaDepartQueryDTO;
import com.engine4cloud.tdf.admin.api.dto.AreaQueryDTO;
import com.engine4cloud.tdf.admin.api.entity.SysDept;
import com.engine4cloud.tdf.admin.api.feign.RemoteAreaService;
import com.engine4cloud.tdf.admin.api.feign.RemoteDeptService;
import com.engine4cloud.tdf.admin.api.vo.AreaResultVO;
import com.engine4cloud.tdf.common.core.constant.SecurityConstants;
import com.engine4cloud.tdf.common.core.constant.enums.AllAuditActionStatusEnum;
import com.engine4cloud.tdf.common.core.constant.enums.AuditBusinessTypeEnum;
import com.engine4cloud.tdf.common.core.constant.enums.CorFileTypeEnum;
import com.engine4cloud.tdf.common.core.constant.enums.NormalAuditActionStatusEnum;
import com.engine4cloud.tdf.common.core.exception.ValidateCodeException;
import com.engine4cloud.tdf.common.core.util.R;
import com.engine4cloud.tdf.common.core.util.RetOps;
import com.engine4cloud.tdf.common.data.web.query.Pages;
import com.engine4cloud.tdf.common.data.web.query.Queries;
import com.engine4cloud.tdf.common.data.web.response.PageInfo;
import com.engine4cloud.tdf.common.data.web.response.Params;
import com.engine4cloud.tdf.common.security.service.TdfUser;
import com.engine4cloud.tdf.common.security.util.SecurityUtils;
import com.engine4cloud.tdf.supervision.convert.SpMigrateConvert;
import com.engine4cloud.tdf.supervision.dto.create.SpAuditActionResultCreateDTO;
import com.engine4cloud.tdf.supervision.dto.create.SpMigrateCreateDTO;
import com.engine4cloud.tdf.supervision.dto.query.JzdxFileQueryDTO;
import com.engine4cloud.tdf.supervision.dto.query.SpMigrateQueryDTO;
import com.engine4cloud.tdf.supervision.dto.result.JzdxResultDTO;
import com.engine4cloud.tdf.supervision.dto.result.SpMigrateResultDTO;
import com.engine4cloud.tdf.supervision.dto.update.SpMigrateUpdateDTO;
import com.engine4cloud.tdf.supervision.dto.update.SpNormalPreActionUpdateDTO;
import com.engine4cloud.tdf.supervision.entity.SpMigrateEntity;
import com.engine4cloud.tdf.supervision.mapper.SpMigrateMapper;
import com.engine4cloud.tdf.supervision.service.JzdxFileService;
import com.engine4cloud.tdf.supervision.service.JzdxService;
import com.engine4cloud.tdf.supervision.service.SpAuditResultService;
import com.engine4cloud.tdf.supervision.service.SpMigrateService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Objects;
import java.util.Optional;

/**
 * 迁居
 *
 * @author wenjie
 * @date 2024-05-30 15:21:31
 */
@Service
public class SpMigrateServiceImpl extends ServiceImpl<SpMigrateMapper, SpMigrateEntity> implements SpMigrateService {
    @Resource
    private JzdxService jzdxService;

    @Resource
    private SpAuditResultService auditResultService;

    @Resource
    private RemoteAreaService areaService;

    @Resource
    private RemoteDeptService remoteDeptService;

    @Resource
    private JzdxFileService fileService;

    @Override
    public PageInfo<SpMigrateResultDTO> pageList(Params pageable, SpMigrateQueryDTO dto) {
        IPage<SpMigrateEntity> page = super.page(Pages.page(pageable), wrapper(dto));
        return Pages.convert(page, SpMigrateConvert.INSTANCE::convertTo);
    }

    @Override
    public SpMigrateResultDTO getById(Long id) {
        SpMigrateEntity entity = Optional.ofNullable(super.getById(id))
                .orElseThrow(() -> new ValidateCodeException("数据不存在"));

        R<AreaResultVO> remoteCounty = areaService.getAreaDetail(new AreaQueryDTO(entity.getQrdqx()),
                SecurityConstants.FROM_IN);
        AreaResultVO county = RetOps.of(remoteCounty).getData()
                .orElseThrow(() -> new ValidateCodeException("原居住地（区县）不正确"));

        R<AreaResultVO> remoteCity = areaService.getAreaDetail(new AreaQueryDTO(county.getPcode()),
                SecurityConstants.FROM_IN);
        AreaResultVO city = RetOps.of(remoteCity).getData()
                .orElseThrow(() -> new ValidateCodeException("原居住地（州、市）不正确"));

        SpMigrateResultDTO result = SpMigrateConvert.INSTANCE.convert(city, entity);
        //设置法律文书信息
        this.setInstrumentList(result);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean create(SpMigrateCreateDTO dto) {
        JzdxResultDTO dx = Optional.ofNullable(jzdxService.getByCode(dto.getRybh()))
                .orElseThrow(() -> new ValidateCodeException("矫正对象数据不存在"));
        TdfUser user = SecurityUtils.getUser();
        //迁居地址信息
        SpMigrateEntity entity = this.prepareEntity(dto,
                null,
                dto.getSourceAreaList().get(dto.getSourceAreaList().size() - 2),
                Long.parseLong(dto.getSourceAreaList().get(dto.getSourceAreaList().size() - 1)),
                Long.parseLong(dto.getTargetAreaList().get(dto.getTargetAreaList().size() - 1)),
                user.getDeptId()
        );
        super.save(entity);
        //保存法律文书（附件）信息
        this.saveInstrumentList(dto, entity, user);
        //设置审核信息
        return auditResultService.create(
                new SpAuditActionResultCreateDTO(
                        entity.getRybh(),
                        entity.getLcbh(),
                        "",
                        AuditBusinessTypeEnum.MIGRATE,
                        AllAuditActionStatusEnum.CREATE,
                        user.getUsername(),
                        entity.getTenantId(),
                        user.getDeptId()
                ));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean update(SpMigrateUpdateDTO dto) {
        SpMigrateEntity old = Optional.ofNullable(super.getById(dto.getId()))
                .orElseThrow(() -> new ValidateCodeException("数据不存在"));
        TdfUser user = SecurityUtils.getUser();
        //迁居地址信息
        SpMigrateEntity entity = this.prepareEntity(null,
                dto,
                dto.getSourceAreaList().get(dto.getSourceAreaList().size() - 2),
                Long.parseLong(dto.getSourceAreaList().get(dto.getSourceAreaList().size() - 1)),
                Long.parseLong(dto.getTargetAreaList().get(dto.getTargetAreaList().size() - 1)),
                user.getDeptId()
        );
        super.updateById(entity);
        //更新法律文书信息
        this.updateInstrumentList(dto, old, user);
        return true;
    }

    @Override
    public SpMigrateResultDTO getByBatch(String batch) {
        return SpMigrateConvert.INSTANCE.convertTo(super.getOne(wrapper(new SpMigrateQueryDTO(batch))));
    }

    @Override
    public void changeAction(SpNormalPreActionUpdateDTO dto) {
        SpMigrateEntity entity = Optional.ofNullable(this.getOne(wrapper(new SpMigrateQueryDTO(dto.getRybh(), dto.getLcbh()))))
                .orElseThrow(() -> new ValidateCodeException("数据不存在"));

        entity.setPreAction(dto.getAction());
        super.updateById(entity);
    }

    private SpMigrateEntity prepareEntity(SpMigrateCreateDTO create, SpMigrateUpdateDTO update, String countyCode, Long sourceVillageId, Long targetVillageId, Long tenantId) {
        R<AreaResultVO> remoteSourceCounty = areaService.getAreaDetail(new AreaQueryDTO(countyCode), SecurityConstants.FROM_IN);
        AreaResultVO sourceCounty = RetOps.of(remoteSourceCounty).getData()
                .orElseThrow(() -> new ValidateCodeException("原居住地（区县）不正确"));

        R<AreaResultVO> remoteSourceVillage = areaService.getAreaDetail(new AreaQueryDTO(sourceCounty.getCode(), sourceVillageId),
                SecurityConstants.FROM_IN);
        AreaResultVO sourceVillage = RetOps.of(remoteSourceVillage).getData()
                .orElseThrow(() -> new ValidateCodeException("原居住地（乡镇、街道）不正确"));

        //迁入地和原居住地的区县是一致的，这里直接取原居住地区县编码
        R<AreaResultVO> remoteTargetVillage = areaService.getAreaDetail(new AreaQueryDTO(sourceCounty.getCode(), targetVillageId),
                SecurityConstants.FROM_IN);
        AreaResultVO targetVillage = RetOps.of(remoteTargetVillage).getData()
                .orElseThrow(() -> new ValidateCodeException("迁入地选择错误，只能迁入到执行地所在乡镇街道"));

        //获取迁入地区县编码
        R<SysDept> deptRemote = remoteDeptService.geDetailByOrgCode(new AreaDepartQueryDTO(sourceCounty.getCode(), "3"), SecurityConstants.FROM_IN);
        SysDept dept = RetOps.of(deptRemote).getData()
                .orElseThrow(() -> new ValidateCodeException("迁入目的地区县没有对应的矫正机构"));

        if (Objects.nonNull(create)) {
            return SpMigrateConvert.INSTANCE.create(create, sourceCounty, sourceVillage, targetVillage, dept, tenantId, NormalAuditActionStatusEnum.CREATE);
        }
        return SpMigrateConvert.INSTANCE.update(update, sourceCounty, sourceVillage, targetVillage, dept);
    }

    public void saveInstrumentList(SpMigrateCreateDTO dto, SpMigrateEntity entity, TdfUser user) {
        fileService.batchSaveFile(new JzdxFileQueryDTO(entity.getRybh(), entity.getLcbh(), CorFileTypeEnum.CORRECTOR_MIGRATE), dto.getInstrumentList(), user);
    }

    private void updateInstrumentList(SpMigrateUpdateDTO dto, SpMigrateEntity entity, TdfUser user) {
        fileService.batchUpdateFile(new JzdxFileQueryDTO(entity.getRybh(), entity.getLcbh(), CorFileTypeEnum.CORRECTOR_MIGRATE), dto.getInstrumentList(), user);
    }

    private void setInstrumentList(SpMigrateResultDTO dto) {
        JzdxFileQueryDTO query = new JzdxFileQueryDTO(dto.getRybh(), dto.getLcbh(), CorFileTypeEnum.CORRECTOR_MIGRATE);
        dto.setInstrumentList(fileService.findList(query));
    }

    private LambdaQueryWrapper<SpMigrateEntity> wrapper(SpMigrateQueryDTO query) {
        LambdaQueryWrapper<SpMigrateEntity> wrapper = Queries.lambda();
        Queries.accept(query.getId(), v -> wrapper.eq(SpMigrateEntity::getId, v));
        Queries.accept(query.getRybh(), v -> wrapper.eq(SpMigrateEntity::getRybh, v));
        Queries.accept(query.getLcbh(), v -> wrapper.eq(SpMigrateEntity::getLcbh, v));
        Queries.accept(query.getPreAction(), v -> wrapper.eq(SpMigrateEntity::getPreAction, v));
        return wrapper;
    }
}